//#region Header
///**
// * JsonReader.cs
// *   Stream-like access to JSON text.
// *
// * The authors disclaim copyright to this source code. For more details, see
// * the COPYING file included with this distribution.
// **/
//#endregion


//using System;
//using System.Collections.Generic;
//using System.IO;
//using System.Text;


//namespace LitJson
//{
//    public enum JsonToken
//    {
//        None,

//        ObjectStart,
//        PropertyName,
//        ObjectEnd,

//        ArrayStart,
//        ArrayEnd,

//        Int,
//        Long,
//        Double,

//        String,

//        Boolean,
//        Null
//    }


//    public class JsonReader
//    {
//        #region Fields
//        private static IDictionary<int, IDictionary<int, int[]>> parse_table;

//        private Stack<int>    automaton_stack;
//        private int           current_input;
//        private int           current_symbol;
//        private bool          end_of_json;
//        private bool          end_of_input;
//        private Lexer         lexer;
//        private bool          parser_in_string;
//        private bool          parser_return;
//        private bool          read_started;
//        private TextReader    reader;
//        private bool          reader_is_owned;
//        private bool          skip_non_members;
//        private object        token_value;
//        private JsonToken     token;
//        #endregion


//        #region Public Properties
//        public bool AllowComments {
//            get { return lexer.AllowComments; }
//            set { lexer.AllowComments = value; }
//        }

//        public bool AllowSingleQuotedStrings {
//            get { return lexer.AllowSingleQuotedStrings; }
//            set { lexer.AllowSingleQuotedStrings = value; }
//        }

//        public bool SkipNonMembers {
//            get { return skip_non_members; }
//            set { skip_non_members = value; }
//        }

//        public bool EndOfInput {
//            get { return end_of_input; }
//        }

//        public bool EndOfJson {
//            get { return end_of_json; }
//        }

//        public JsonToken Token {
//            get { return token; }
//        }

//        public object Value {
//            get { return token_value; }
//        }
//        #endregion


//        #region Constructors
//        static JsonReader ()
//        {
//            PopulateParseTable ();
//        }

//        public JsonReader (string json_text) :
//            this (new StringReader (json_text), true)
//        {
//        }

//        public JsonReader (TextReader reader) :
//            this (reader, false)
//        {
//        }

//        private JsonReader (TextReader reader, bool owned)
//        {
//            if (reader == null)
//                throw new ArgumentNullException ("reader");

//            parser_in_string = false;
//            parser_return    = false;

//            read_started = false;
//            automaton_stack = new Stack<int> ();
//            automaton_stack.Push ((int) ParserToken.End);
//            automaton_stack.Push ((int) ParserToken.Text);

//            lexer = new Lexer (reader);

//            end_of_input = false;
//            end_of_json  = false;

//            skip_non_members = true;

//            this.reader = reader;
//            reader_is_owned = owned;
//        }
//        #endregion


//        #region Static Methods
//        private static void PopulateParseTable ()
//        {
//            // See section A.2. of the manual for details
//            parse_table = new Dictionary<int, IDictionary<int, int[]>> ();

//            TableAddRow (ParserToken.Array);
//            TableAddCol (ParserToken.Array, '[',
//                         '[',
//                         (int) ParserToken.ArrayPrime);

//            TableAddRow (ParserToken.ArrayPrime);
//            TableAddCol (ParserToken.ArrayPrime, '"',
//                         (int) ParserToken.Value,

//                         (int) ParserToken.ValueRest,
//                         ']');
//            TableAddCol (ParserToken.ArrayPrime, '[',
//                         (int) ParserToken.Value,
//                         (int) ParserToken.ValueRest,
//                         ']');
//            TableAddCol (ParserToken.ArrayPrime, ']',
//                         ']');
//            TableAddCol (ParserToken.ArrayPrime, '{',
//                         (int) ParserToken.Value,
//                         (int) ParserToken.ValueRest,
//                         ']');
//            TableAddCol (ParserToken.ArrayPrime, (int) ParserToken.Number,
//                         (int) ParserToken.Value,
//                         (int) ParserToken.ValueRest,
//                         ']');
//            TableAddCol (ParserToken.ArrayPrime, (int) ParserToken.True,
//                         (int) ParserToken.Value,
//                         (int) ParserToken.ValueRest,
//                         ']');
//            TableAddCol (ParserToken.ArrayPrime, (int) ParserToken.False,
//                         (int) ParserToken.Value,
//                         (int) ParserToken.ValueRest,
//                         ']');
//            TableAddCol (ParserToken.ArrayPrime, (int) ParserToken.Null,
//                         (int) ParserToken.Value,
//                         (int) ParserToken.ValueRest,
//                         ']');

//            TableAddRow (ParserToken.Object);
//            TableAddCol (ParserToken.Object, '{',
//                         '{',
//                         (int) ParserToken.ObjectPrime);

//            TableAddRow (ParserToken.ObjectPrime);
//            TableAddCol (ParserToken.ObjectPrime, '"',
//                         (int) ParserToken.Pair,
//                         (int) ParserToken.PairRest,
//                         '}');
//            TableAddCol (ParserToken.ObjectPrime, '}',
//                         '}');

//            TableAddRow (ParserToken.Pair);
//            TableAddCol (ParserToken.Pair, '"',
//                         (int) ParserToken.String,
//                         ':',
//                         (int) ParserToken.Value);

//            TableAddRow (ParserToken.PairRest);
//            TableAddCol (ParserToken.PairRest, ',',
//                         ',',
//                         (int) ParserToken.Pair,
//                         (int) ParserToken.PairRest);
//            TableAddCol (ParserToken.PairRest, '}',
//                         (int) ParserToken.Epsilon);

//            TableAddRow (ParserToken.String);
//            TableAddCol (ParserToken.String, '"',
//                         '"',
//                         (int) ParserToken.CharSeq,
//                         '"');

//            TableAddRow (ParserToken.Text);
//            TableAddCol (ParserToken.Text, '[',
//                         (int) ParserToken.Array);
//            TableAddCol (ParserToken.Text, '{',
//                         (int) ParserToken.Object);

//            TableAddRow (ParserToken.Value);
//            TableAddCol (ParserToken.Value, '"',
//                         (int) ParserToken.String);
//            TableAddCol (ParserToken.Value, '[',
//                         (int) ParserToken.Array);
//            TableAddCol (ParserToken.Value, '{',
//                         (int) ParserToken.Object);
//            TableAddCol (ParserToken.Value, (int) ParserToken.Number,
//                         (int) ParserToken.Number);
//            TableAddCol (ParserToken.Value, (int) ParserToken.True,
//                         (int) ParserToken.True);
//            TableAddCol (ParserToken.Value, (int) ParserToken.False,
//                         (int) ParserToken.False);
//            TableAddCol (ParserToken.Value, (int) ParserToken.Null,
//                         (int) ParserToken.Null);

//            TableAddRow (ParserToken.ValueRest);
//            TableAddCol (ParserToken.ValueRest, ',',
//                         ',',
//                         (int) ParserToken.Value,
//                         (int) ParserToken.ValueRest);
//            TableAddCol (ParserToken.ValueRest, ']',
//                         (int) ParserToken.Epsilon);
//        }

//        private static void TableAddCol (ParserToken row, int col,
//                                         params int[] symbols)
//        {
//            parse_table[(int) row].Add (col, symbols);
//        }

//        private static void TableAddRow (ParserToken rule)
//        {
//            parse_table.Add ((int) rule, new Dictionary<int, int[]> ());
//        }
//        #endregion


//        #region Private Methods
//        private void ProcessNumber (string number)
//        {
//            if (number.IndexOf ('.') != -1 ||
//                number.IndexOf ('e') != -1 ||
//                number.IndexOf ('E') != -1) {

//                double n_double;
//                if (Double.TryParse (number, out n_double)) {
//                    token = JsonToken.Double;
//                    token_value = n_double;

//                    return;
//                }
//            }

//            int n_int32;
//            if (Int32.TryParse (number, out n_int32)) {
//                token = JsonToken.Int;
//                token_value = n_int32;

//                return;
//            }

//            long n_int64;
//            if (Int64.TryParse (number, out n_int64)) {
//                token = JsonToken.Long;
//                token_value = n_int64;

//                return;
//            }

//            ulong n_uint64;
//            if (UInt64.TryParse(number, out n_uint64))
//            {
//                token = JsonToken.Long;
//                token_value = n_uint64;

//                return;
//            }

//            // Shouldn't happen, but just in case, return something
//            token = JsonToken.Int;
//            token_value = 0;
//        }

//        private void ProcessSymbol ()
//        {
//            if (current_symbol == '[')  {
//                token = JsonToken.ArrayStart;
//                parser_return = true;

//            } else if (current_symbol == ']')  {
//                token = JsonToken.ArrayEnd;
//                parser_return = true;

//            } else if (current_symbol == '{')  {
//                token = JsonToken.ObjectStart;
//                parser_return = true;

//            } else if (current_symbol == '}')  {
//                token = JsonToken.ObjectEnd;
//                parser_return = true;

//            } else if (current_symbol == '"')  {
//                if (parser_in_string) {
//                    parser_in_string = false;

//                    parser_return = true;

//                } else {
//                    if (token == JsonToken.None)
//                        token = JsonToken.String;

//                    parser_in_string = true;
//                }

//            } else if (current_symbol == (int) ParserToken.CharSeq) {
//                token_value = lexer.StringValue;

//            } else if (current_symbol == (int) ParserToken.False)  {
//                token = JsonToken.Boolean;
//                token_value = false;
//                parser_return = true;

//            } else if (current_symbol == (int) ParserToken.Null)  {
//                token = JsonToken.Null;
//                parser_return = true;

//            } else if (current_symbol == (int) ParserToken.Number)  {
//                ProcessNumber (lexer.StringValue);

//                parser_return = true;

//            } else if (current_symbol == (int) ParserToken.Pair)  {
//                token = JsonToken.PropertyName;

//            } else if (current_symbol == (int) ParserToken.True)  {
//                token = JsonToken.Boolean;
//                token_value = true;
//                parser_return = true;

//            }
//        }

//        private bool ReadToken ()
//        {
//            if (end_of_input)
//                return false;

//            lexer.NextToken ();

//            if (lexer.EndOfInput) {
//                Close ();

//                return false;
//            }

//            current_input = lexer.Token;

//            return true;
//        }
//        #endregion


//        public void Close ()
//        {
//            if (end_of_input)
//                return;

//            end_of_input = true;
//            end_of_json  = true;

//            if (reader_is_owned)
//                reader.Close ();

//            reader = null;
//        }

//        public bool Read ()
//        {
//            if (end_of_input)
//                return false;

//            if (end_of_json) {
//                end_of_json = false;
//                automaton_stack.Clear ();
//                automaton_stack.Push ((int) ParserToken.End);
//                automaton_stack.Push ((int) ParserToken.Text);
//            }

//            parser_in_string = false;
//            parser_return    = false;

//            token       = JsonToken.None;
//            token_value = null;

//            if (! read_started) {
//                read_started = true;

//                if (! ReadToken ())
//                    return false;
//            }


//            int[] entry_symbols;

//            while (true) {
//                if (parser_return) {
//                    if (automaton_stack.Peek () == (int) ParserToken.End)
//                        end_of_json = true;

//                    return true;
//                }

//                current_symbol = automaton_stack.Pop ();

//                ProcessSymbol ();

//                if (current_symbol == current_input) {
//                    if (! ReadToken ()) {
//                        if (automaton_stack.Peek () != (int) ParserToken.End)
//                            throw new JsonException (
//                                "Input doesn't evaluate to proper JSON text");

//                        if (parser_return)
//                            return true;

//                        return false;
//                    }

//                    continue;
//                }

//                try {

//                    entry_symbols =
//                        parse_table[current_symbol][current_input];

//                } catch (KeyNotFoundException e) {
//                    throw new JsonException ((ParserToken) current_input, e);
//                }

//                if (entry_symbols[0] == (int) ParserToken.Epsilon)
//                    continue;

//                for (int i = entry_symbols.Length - 1; i >= 0; i--)
//                    automaton_stack.Push (entry_symbols[i]);
//            }
//        }

//    }
//}
